/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_Studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "stdafx.h"
#include "点集几何计算.h"
#include "节点/socket_utils.h"
#include <matXX.h>
#include <几何图形/图形相交.h>
#include <core/动画/curve.h>

#include <节点/插座/list/list数值插座.h>
#include <节点/插座/list/list物体插座.h>
#include <节点/插座/list/list矢量插座.h>
#include <节点/插座/list/list物理物体插座.h>
#include <节点/插座/通用插座.h>

#include "Context/当前默认操作数据.h"


#include "计算类JIT函数.h"

#include "节点/节点树.h"


static float32 g防止除0补偿值 = 0.00000001f;



C_初始化点集约束到变换节点::C_初始化点集约束到变换节点(S_设备环境& ctx) : C_节点基类("初始化点集转变换节点") {
	m_Ctx = ctx;
	m_Name = L"初始化点集转变换";


	C_插座基类* socket;
	DEF_创建Vec3_Array1D插座_I(L"点集");
	DEF_创建F32_Array1D插座_I(L"质量");

	//DEF_创建Vec3_1D插座_O("新点集");
	DEF_创建mat3X3插座_O(L"旋转矩阵");
	DEF_创建Vec3插座_O(L"中心坐标");
}

C_初始化点集约束到变换节点::~C_初始化点集约束到变换节点() {


}

bool C_初始化点集约束到变换节点::f_update() {
	auto& points = *DEF_Vec3_Array1D插座数据(f_get输入插座(1));
	auto& 质量 = *DEF_F32_Array1D插座数据(f_get输入插座(2));

	auto& 旋转矩阵 = *DEF_Mat3X3插座数据(f_get输出插座(1));
	auto& 中心坐标 = DEF_Vec3插座数据(f_get输出插座(2));
	中心坐标 = {};
	f_mat_zero(旋转矩阵);


	uint64 num = points.size();
	bool 统一质量 = false;
	if (质量.size() < 1) return false;
	if (质量.size() < num) 统一质量 = true;

	vec3* p_points = points.data();
	float32* p_质量 = 质量.data();

	float32 权重和 = 0;
#pragma omp parallel for
	for (int64 i = 0; i < num; ++i) {
		float32 权重 = 1.0f / (统一质量 ?  p_质量[0] + g防止除0补偿值 : p_质量[i] + g防止除0补偿值);
		vec_add(&中心坐标, vec_mul(p_points[i], 权重));
		//p_outData[i] = !p_dataA[i];
		权重和 += 权重;
	}

	if (权重和 != 0) {
		vec_div(&中心坐标, 权重和);

		C_Mat33 rm;
		rm.cols[0] = {};
		rm.cols[1] = {};
		rm.cols[2] = {};

#pragma omp parallel for
		for (int64 i = 0; i < num; ++i) {
			vec3 q = vec_sub(p_points[i], 中心坐标);
			float32 权重 = 1.0f / (统一质量 ? p_质量[0] + g防止除0补偿值 : p_质量[i] + g防止除0补偿值);
			//float32 权重 = 1.0f / (p_质量[i] + 0.0000001) * 0.01f;

			float32 x2 = 权重 * q.x * q.x;
			float32 y2 = 权重 * q.y * q.y;
			float32 z2 = 权重 * q.z * q.z;
			float32 xy = 权重 * q.x * q.y;
			float32 xz = 权重 * q.x * q.z;
			float32 yz = 权重 * q.y * q.z;

			/*float32 x2 = 权重 * q.x;
			float32 y2 = 权重 * q.y;
			float32 z2 = 权重 * q.z;
			float32 xy = 权重 * q.x;
			float32 xz = 权重 * q.x;
			float32 yz = 权重 * q.y;*/

			旋转矩阵.row0.x += x2;
			旋转矩阵.row0.y += xy;
			旋转矩阵.row0.z += xz;

			旋转矩阵.row1.x += xy;
			旋转矩阵.row1.y += y2;
			旋转矩阵.row1.z += yz;

			旋转矩阵.row2.x += xz;
			旋转矩阵.row2.y += yz;
			旋转矩阵.row2.z += z2;

			/*旋转矩阵.row0.x += x2;
			旋转矩阵.row1.x += xy;
			旋转矩阵.row2.x += xz;

			旋转矩阵.row0.y += xy;
			旋转矩阵.row1.y += y2;
			旋转矩阵.row2.y += yz;

			旋转矩阵.row0.z += xz;
			旋转矩阵.row1.z += yz;
			旋转矩阵.row2.z += z2;*/

			
			rm.cols[0].x += x2;
			rm.cols[0].y += xy;
			rm.cols[0].z += xz;

			rm.cols[1].x += xy;
			rm.cols[1].y += y2;
			rm.cols[1].z += yz;

			rm.cols[2].x += xz;
			rm.cols[2].y += yz;
			rm.cols[2].z += z2;

			/*rm.cols[0].x += x2;
			rm.cols[1].x += xy;
			rm.cols[2].x += xz;

			rm.cols[0].y += xy;
			rm.cols[1].y += y2;
			rm.cols[2].y += yz;

			rm.cols[0].z += xz;
			rm.cols[1].z += yz;
			rm.cols[2].z += z2;*/
		}


		//f_求逆矩阵(rm);
		//f_mat_转换(旋转矩阵, rm);
		旋转矩阵 = f_mat3x3_T(旋转矩阵);
	}
	else {
		中心坐标 = {};
	}

	return false;
}

C_节点基类* f_node_加载初始化点集约束到变换节点(S_设备环境& ctx, FILE* f) {
	C_初始化点集约束到变换节点* node = new C_初始化点集约束到变换节点(ctx);

	return node;
}

void f_node_保存初始化点集约束到变换节点(C_节点基类* n, FILE* f) {
	C_初始化点集约束到变换节点* node = dynamic_cast<C_初始化点集约束到变换节点*>(n);

}









C_点集约束到变换节点::C_点集约束到变换节点(S_设备环境& ctx) : C_节点基类("点集转变换节点") {
	m_Ctx = ctx;
	m_Name = L"点集转变换节点";
	

	C_插座基类* socket;
	DEF_创建Vec3_Array1D插座_I(L"点集");
	DEF_创建Vec3_Array1D插座_I(L"新点集");
	DEF_创建F32_Array1D插座_I(L"质量");
	
	DEF_创建mat3X3插座_I(L"旋转矩阵");
	DEF_创建Vec3插座_v1_I(L"中心坐标");

	

	DEF_创建Quat插座_O(L"quat");
	DEF_创建Vec3_Array1D插座_O(L"变换后点集");
}

C_点集约束到变换节点::~C_点集约束到变换节点() {

}

bool C_点集约束到变换节点::f_update() {
	auto& points0 = *DEF_Vec3_Array1D插座数据(f_get输入插座(1));
	auto& points = *DEF_Vec3_Array1D插座数据(f_get输入插座(2));
	auto& 质量 = *DEF_F32_Array1D插座数据(f_get输入插座(3));

	const auto& 原始旋转矩阵 = f_mat_转换(*DEF_Mat3X3插座数据(f_get输入插座(4)));
	const auto& 原始中心坐标 = DEF_Vec3插座数据(f_get输入插座(5));
	

	auto& quat = *DEF_Quat插座数据(f_get输出插座(1));
	//auto& 中心坐标 = *DEF_Vec3插座数据(f_get输出插座(2));
	auto& 变换后点集 = *DEF_Vec3_Array1D插座数据(f_get输出插座(2));





	int64 num = points.size();

	bool 统一质量 = false;
	if (质量.size() < 1) return false;
	if (质量.size() < num) 统一质量 = true;
	变换后点集.resize(num);


	vec3* p_points0 = points0.data();
	vec3* p_points = points.data();
	vec3* p_newPoints = 变换后点集.data();
	float32* p_质量 = 质量.data();


	vec3 中心坐标0 = {};
	vec3 中心坐标 = {};
	float32 权重和 = 0;
	quat = { 0,0,0,1 };




	for (int64 i = 0; i < num; ++i) {
		float32 权重 = 1.0f / (统一质量 ? p_质量[0] + g防止除0补偿值 : p_质量[i] + g防止除0补偿值);
		权重和 += 权重;

		vec_add(&中心坐标0, vec_mul(p_points0[i], 权重));
		vec_add(&中心坐标, vec_mul(p_points[i], 权重));

	}

	if (权重和 != 0) {


		vec3 位移向量 = vec_sub(中心坐标, 中心坐标0);
		float32 移动距离 = vec_normalize(&位移向量);

		vec_div(&中心坐标0, 权重和);
		vec_div(&中心坐标, 权重和);


		vec3 撞击方向 = {};
		float32 撞击强度 = 0;
		float32 最小 = 0;
		float32 最大 = 0;
		for (int64 i = 0; i < num; ++i) {
			float32 权重 = 1.0f / (统一质量 ? p_质量[0] + g防止除0补偿值 : p_质量[i] + g防止除0补偿值);

			vec3 q0 = vec_sub(p_points[i], p_points0[i]);
			vec_mul(&q0, 权重);
			float32 l = vec_normalize(&q0);
			//vec3 q0 = vec_sub(p_points0[i], 中心坐标0);
			vec3 q = vec_normalize2(vec_sub(p_points[i], 中心坐标));

			//vec_add(&撞击方向, vec_multi(vec_cross(q0, q), l));
			vec_add(&撞击方向, vec_cross(q0, q));
			//vec_add(&撞击方向, vec_sub(q, q0));
			权重 = vec_dot(q0, q);
			最小 = DEF_Min(最小, 权重);
			最大 = DEF_Max(最大, 权重);

			撞击强度 += l;

		}
		vec_mul(&撞击方向, 撞击强度);
		float32 l = vec_normalize(&撞击方向);
		//撞击强度 /= num;
		l = (1.0 - 最大) + (1.0 + 最小);

		//f_欧拉角转四元数()
		quat.x = 撞击方向.x;
		quat.y = 撞击方向.y;
		quat.z = 撞击方向.z;
		quat.w = l;
	}
	return false;
	


	//================================ 老的实现 ========================================
//#pragma omp parallel for
	for (int64 i = 0; i < num; ++i) {
		float32 权重 = 1.0f / (统一质量 ? p_质量[0] + g防止除0补偿值 : p_质量[i] + g防止除0补偿值);
		vec_add(&中心坐标, vec_mul(p_points[i], 权重));
		//p_outData[i] = !p_dataA[i];
		权重和 += 权重;
	}

	if (权重和 != 0) {
		vec_div(&中心坐标, 权重和);


		C_Mat33 mat;
		//mat3X3 mat = {};
		//f_mat_zero(mat);
//#pragma omp parallel for
		for (int64 i = 0; i < num; ++i) {
			vec3 q = vec_sub(p_points0[i], 原始中心坐标);
			vec3 p = vec_sub(p_points[i], 中心坐标);
			float32 权重 = 1.0f / (统一质量 ? p_质量[0] + g防止除0补偿值 : p_质量[i] + g防止除0补偿值);
			//float32 权重 = 1.0f / (p_质量[i] + 0.0000001);
			vec_mul(&p, 权重);


			mat.cols[0].x += p.x * q.x;
			mat.cols[0].y += p.x * q.y;
			mat.cols[0].z += p.x * q.z;

			mat.cols[1].x += p.y * q.x;
			mat.cols[1].y += p.y * q.y;
			mat.cols[1].z += p.y * q.z;

			mat.cols[2].x += p.y * q.x;
			mat.cols[2].y += p.y * q.y;
			mat.cols[2].z += p.y * q.z;

			/*mat.row0.x += p.x * q.x;
			mat.row0.y += p.x * q.y;
			mat.row0.z += p.x * q.z;

			mat.row1.x += p.y * q.x;
			mat.row1.y += p.y * q.y;
			mat.row1.z += p.y * q.z;

			mat.row2.x += p.y * q.x;
			mat.row2.y += p.y * q.y;
			mat.row2.z += p.y * q.z;*/

		}


		//mat = f_矩阵相乘(mat, 原始旋转矩阵);
		mat = mat * 原始旋转矩阵;
		//auto q = f_mat_四元数转44矩阵(quat);
		
		
		//vec4 旋转四元数 = mat3x3_quat(mat);
		for (uint8 iter = 0; iter < 1; ++iter) {

			/*mat3X3 q = mat3x3(旋转四元数);

			vec3 Oa = vec_cross(mat.row0, q.row0);
			vec_add(&Oa, vec_cross(mat.row1, q.row1));
			vec_add(&Oa, vec_cross(mat.row2, q.row2));

			float32 Ob = vec_dot(mat.row0, q.row0);
			Ob += vec_dot(mat.row1, q.row1);
			Ob += vec_dot(mat.row2, q.row2) + 0.00000001;
			Ob = 1.0f / fabs(Ob);

			vec_multi(&Oa, Ob);

			float32 w = vec_normalize((vec3*)&Oa);
			if (w < 0.000000001) {
				break;
			}
			vec4 tq; tq.x = Oa.x; tq.y = Oa.y; tq.z = Oa.z;
			vec_multi(&tq, (1.0f / w));
			tq.w = w;
			vec_multi(&旋转四元数, tq);
			vec_normalize(旋转四元数);*/


			C_Mat33 q(quat);
			Vec3 Oa = f_mat_差积(mat.cols[0], q.cols[0]);
			Oa += f_mat_差积(mat.cols[1], q.cols[1]);
			Oa += f_mat_差积(mat.cols[2], q.cols[2]);
			Vec3 Ob = 1.0f / fabs(Dot(mat.cols[0], q.cols[0]));
			Ob += 1.0f / fabs(Dot(mat.cols[1], q.cols[1]));
			Ob += 1.0f / fabs(Dot(mat.cols[2], q.cols[2]) + 0.00000001);

			Oa *= Ob;
			float32 w = vec_normalize((vec3*)&Oa);
			if (w < 0.000000001) {
				break;
			}

			quat = QuatFromAxisAngle(Oa * (1.0f / w), w);
			quat = Normalize(quat);
			//Quat tq(Oa * (1.0f / w), w);
			//quat = tq * quat;
			
		}
		/*quat.x = 旋转四元数.x;
		quat.y = 旋转四元数.y;
		quat.z = 旋转四元数.z;
		quat.w = 旋转四元数.w;*/


//#pragma omp parallel for
		for (int64 i = 0; i < num; ++i) {
			//vec3 旋转变换后的坐标 = vec_add(中心坐标, f_quat_Rotate(*((vec4*)&quat), vec_sub(p_points0[i], 原始中心坐标)));
			vec3 旋转变换后的坐标 = vec_add(中心坐标, f_quat_Rotate(*((vec4*)&quat), vec_sub(p_points0[i], 原始中心坐标)));
			p_newPoints[i] = vec_mul(vec_sub(旋转变换后的坐标, p_points[i]), 1.0);
			vec_add(&p_newPoints[i], p_points0[i]);
		}
	}

		/*for (unsigned int iter = 0; iter < maxIter; iter++)
		{
			Matrix3r R = q.matrix();
			Vector3r omega = (R.col(0).cross(A.col(0)) + R.col(1).cross(A.col(1)) + R.col(2).cross(A.col(2))) *
				(1.0 / fabs(R.col(0).dot(A.col(0)) + R.col(1).dot(A.col(1)) + R.col(2).dot(A.col(2)) + 1.0e-9));
			Real w = omega.norm();
			if (w < 1.0e-9)
				break;
			q = Quaternionr(AngleAxisr(w, (1.0 / w) * omega)) * q;
			q.normalize();
		}*/






	return false;



	
}




C_节点基类* f_node_加载点集约束到变换节点(S_设备环境& ctx, FILE* f) {
	C_点集约束到变换节点* node = new C_点集约束到变换节点(ctx);

	return node;
}

void f_node_保存点集约束到变换节点(C_节点基类* n, FILE* f) {
	C_点集约束到变换节点* node = dynamic_cast<C_点集约束到变换节点*>(n);

}








C_射线物体相交节点::C_射线物体相交节点(S_设备环境& ctx) : C_节点基类(DEF_射线物体相交节点) {
	m_Ctx = ctx;
	m_Name = L"射线相交";
	m_Tree = nullptr;
	m_参数 = {};

	C_插座基类* socket;
	DEF_创建物体_1D插座_I(L"物体");
	DEF_创建Vec3_1D插座_I(L"起始坐标");
	DEF_创建Vec3_1D插座_I(L"入射向量");
	DEF_创建F32_1D插座_I(L"入射向量");
	
	//DEF_创建点距八叉树插座_I(L"TREE");

	DEF_创建Vec3_1D插座_O(L"相交点");
	DEF_创建F32_1D插座_O(L"相交距离");


	m_使用光追线管 = f_alloc_BoolProp(nullptr, L"光追线管");
	m_使用光追线管.m_私有 = true;
	f_prop_Bool(m_使用光追线管) = true;

	m_是否构建八叉树 = f_alloc_BoolProp(nullptr, L"构建八叉树");
	m_是否构建八叉树.m_私有 = true;
	f_prop_Bool(m_是否构建八叉树) = false;
	
	
	std::vector<S_着色器创建参数> 参数配置 = {
		{DEF_BINDING_topLAS, E_着色阶段::e_计算着色, E_板载缓存类型::e_光追BVH},

		{DEF_BINDING_Ray_ObMesh, E_着色阶段::e_计算着色, E_板载缓存类型::e_SSBO},
		//{DEF_BINDING_RayDirection, E_着色阶段::e_计算着色, E_板载缓存类型::e_SSBO},
		//{DEF_BINDING_RayLength, E_着色阶段::e_计算着色, E_板载缓存类型::e_SSBO},
		
		//{DEF_BINDING_RayIntersection, E_着色阶段::e_计算着色, E_板载缓存类型::e_SSBOd},
		//{DEF_BINDING_RayIntersectionDis, E_着色阶段::e_计算着色, E_板载缓存类型::e_SSBOd},
	};

	std::vector<S_着色器常量推送创建参数> 常量 = {
		{E_着色阶段::e_计算着色, 0, sizeof(S_RayIntersectionMemProp)},
	};

	m_GPU计算设备 = f_gpu_create并行计算实例(ctx, S_引擎::m_3D着色器文件根路径 + "物体射线相交.spv", 参数配置, 常量);
	f_allocGPU参数缓存槽(&m_参数, 1);
}

C_射线物体相交节点::~C_射线物体相交节点() {
	f_prop_Release(m_使用光追线管);
	f_prop_Release(m_是否构建八叉树);
}

bool C_射线物体相交节点::f_update() {
	auto* socket1 = f_get输入插座(1);

	auto* socket2 = f_get输入插座(2);
	auto* socket3 = f_get输入插座(3);
	auto* socket4 = f_get输入插座(4);

	auto* socket1Out = f_get输出插座(1);
	auto* socket2Out = f_get输出插座(2);

	auto* inData1 = DEF_物体插座_1D数据(socket1, 0);

	//auto& inData2 = *DEF_Vec3插座_1D数据(f_get输入插座(2), 0);
	//auto& inData3 = *DEF_Vec3插座_1D数据(f_get输入插座(3), 0);
	//auto& inData4 = *DEF_F32插座_1D数据(f_get输入插座(4), 0);
	

	if (f_prop_Bool(m_使用光追线管)) {
		std::set<S_Mesh*> 网格;
		for (uint32 i = 0; i < inData1->count; ++i) {
			S_Mesh* me = f_ob_fromMesh(inData1->ptr_userData[i]);
			if(me) 网格.insert(me);
		}
		for (auto& e : 网格) {
			f_surface_构建光追底层加速结构(e, E_物体类型::t_网格);
		}
		
		for (uint32 i = 0; i < inData1->count; ++i) {
			f_ob_构建光追实例加速结构(inData1->ptr_userData[i], m_Ctx);
		}
		
		auto* scene = f_NodeCtx_get默认场景();
		f_scene_构建顶层光追加速结构(scene, inData1, m_Ctx);


		S_GPU内存块索引 块[5];

		块[0] = socket2->f_getGPU块(0, true);
		块[1] = socket3->f_getGPU块(0, true);
		块[2] = socket4->f_getGPU块(0, true);
		
		uvec3 dim{ 1,1,1 };
		for (uint32 i = 0; i < 3; ++i) {
			dim.x = DEF_Max(dim.x, (块[i]).m_Mem.m_大小);
		}
		f_buf_gresize(socket1Out->f_getGPU块(0, false), dim.x);
		f_buf_gresize(socket2Out->f_getGPU块(0, false), dim.x);
		
		块[3] = socket1Out->f_getGPU块(0, false);
		块[4] = socket2Out->f_getGPU块(0, false);
		
		
		m_参数.m_参数槽[0] = &(scene->m_光追顶层加速结构);
		m_参数.m_参数类型[0] = E_板载缓存类型::e_光追BVH;
		m_参数.m_绑定位置[0] = DEF_BINDING_topLAS;
		m_参数.m_绑定数量[0] = 1;

		m_参数.m_参数槽[1] = &块[0];
		m_参数.m_参数类型[1] = E_板载缓存类型::e_SSBO;
		m_参数.m_绑定位置[1] = DEF_BINDING_RayOrigin;
		m_参数.m_绑定数量[1] = 1;
		


		S_绘图设备* dev = f_df_get绘图环境(m_Ctx);

		S_RayIntersectionMemProp MemProp;
		MemProp.mem_OriginNum = 块[0].m_Mem.m_大小;
		MemProp.mem_DirectionNum = 块[1].m_Mem.m_大小;
		MemProp.mem_RayLengthNum = 块[2].m_Mem.m_大小;
		MemProp.mem_IntersectionPointNum = 块[3].m_Mem.m_大小;
		MemProp.mem_IntersectionDisNum = 块[4].m_Mem.m_大小;

		MemProp.m_Address_Origin = f_buf_getAddress(块[0]);
		MemProp.m_Address_Direction = f_buf_getAddress(块[1]);
		MemProp.m_Address_RayLength = f_buf_getAddress(块[2]);
		MemProp.m_Address_IntersectionPoint = f_buf_getAddress(块[3]);
		MemProp.m_Address_IntersectionDis = f_buf_getAddress(块[4]);
		

		
		MemProp.mem_Flage = 0;
		for (uint32 i = 0; i < 3; ++i) {
			if (块[i].m_Mem.m_大小 >= dim.x) {
				MemProp.mem_Flage |= 1<<i;
			}
		}
		
		f_df_upGPU参数(dev->m_设备, m_GPU计算设备->m_GPU参数set, m_参数);
		f_GPU_run计算(m_GPU计算设备, dim, &MemProp, sizeof(S_RayIntersectionMemProp));
		//f_GPU_run计算(m_GPU计算设备, S_光追后端::m_加速结构创建命令缓存, dim, &MemProp, sizeof(S_RayIntersectionMemProp), S_光追后端::g_光追列队);


		

		socket1Out->f_downGPU块(0);
		socket2Out->f_downGPU块(0);

		//f_buf_release板载缓存(a);
	}
	else {
		if (f_prop_Bool(m_是否构建八叉树)) {
			if (!m_Tree) m_Tree = f_空间划分_create球形八叉树(100000.0);
		}
		else {
			if (m_Tree) f_空间划分_destroy球形八叉树(m_Tree);
		}
	}
	


	//switch (inData2.m_Type) {
	//case E_值类型::e_Type_Object: {
	//	auto* mesh = f_ob_fromMesh(DEF_引用转物体(inData2));
	//	f_计算网格({ mesh });
	//	break;
	//}
	//case E_值类型::e_Type_Object_1D: {
	//	auto& obs = *DEF_引用转物体_1D(inData2);
	//	for (auto& e : obs) {
	//		auto* mesh = f_ob_fromMesh(e);
	//		f_计算网格({ mesh });
	//	}
	//	break;
	//}
	//default:
	//	break;
	//}
	return false;
}

void C_射线物体相交节点::f_计算Vec3(std::vector<vec3>& data) {

}

void C_射线物体相交节点::f_计算Vec4(const std::vector<vec4>& data) {

}

void C_射线物体相交节点::f_计算网格(const std::vector<S_Mesh*>& data) {
	auto& lines = *DEF_线段_1D插座数据(f_get输入插座(1));
	uint32 lineNum = lines.size();
	
	auto& outData1 = *DEF_Vec3_Array1D插座数据(f_get输出插座(1), 0);
	outData1.reserve(10);

	if (!lineNum) return;
	auto* linePtr = lines.data();

	//auto& inData2 = DEF_点距八叉树插座Value(f_get输入插座(3), 0);
	

	for (auto* e : data) {
		std::vector<vec3> verts;
		std::vector<uvec3> indexs;
		f_surface_get顶点坐标(e, verts);
		f_surface_get顶点索引(e, indexs);
		auto* v = verts.data();

		if (m_Tree) {
			f_空间划分_remove所有子集(m_Tree);

			std::vector<S_VecSphere> 包围盒;
			f_surface_计算三角形球体包围盒(e, 包围盒);
			f_空间划分_从坐标索引(m_Tree, 包围盒);


			for (uint32 i = 0; i < lineNum; ++i) {
				vec3 dir = linePtr[i].end - linePtr[i].begin;

				std::vector<S_八叉树子空间*> 相交到的节点;
				f_空间划分_get射线子集数据(m_Tree, linePtr[i].begin, dir, 相交到的节点);
				for (auto l : 相交到的节点) {
					const std::vector<uint32>& 面索引 = *((std::vector<uint32>*)l->m_数据);
					for (auto faceID : 面索引) {
						vec3 coord = {};
						uvec3 trangle = indexs[faceID];

						bool 相交 = f_graph_IntersectTriangle(v[trangle.x], v[trangle.y], v[trangle.z], linePtr[i].begin, dir, &coord);
						if (相交) {
							outData1.push_back(coord);
						}
					}
					
				}
			}

		}
		else {
			for (uint32 i = 0; i < lineNum; ++i) {
				vec3 dir = linePtr[i].end - linePtr[i].begin;

				
				for (auto& e : indexs) {
					vec3 coord = {};
					bool 相交 = f_graph_IntersectTriangle(v[e.x], v[e.y], v[e.z], linePtr[i].begin, dir, &coord);
					if (相交) {
						outData1.push_back(coord);
					}
				}
			}
		}

	}

}

void C_射线物体相交节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;
		if (f_file_版本对比(文件块, S_节点数据::g_低版本号_1, S_节点数据::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_使用光追线管, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_是否构建八叉树, 下一次读取数据指针);
			//f_prop_Load(m_是否改变原数据, f);
			//f_prop_Load(m_执行代码, f);
		}
	}
	free(文件块.m_data);
}
void C_射线物体相交节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_file_构建文件块信息(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_节点数据::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_使用光追线管, 块);
	f_prop_Save(m_是否构建八叉树, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建射线物体相交节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_射线物体相交节点(ctx);
}

C_节点基类* f_node_加载射线物体相交节点(S_设备环境& ctx, FILE* f) {
	C_射线物体相交节点* node = new C_射线物体相交节点(ctx);
	return node;
}

void f_node_保存射线物体相交节点(C_节点基类* n, FILE* f) {
	C_射线物体相交节点* node = dynamic_cast<C_射线物体相交节点*>(n);
}



C_圆坐标生成节点::C_圆坐标生成节点(S_设备环境& ctx) : C_节点基类(DEF_圆坐标生成节点) {
	m_Ctx = ctx;
	m_Name = L"圆坐标";

	C_插座基类* socket;
	DEF_创建F32插座_I(L"半径", nullptr);
	DEF_创建UI32插座_I(L"细分", nullptr);
	
	DEF_创建Vec3_1D插座_O(L"顶点坐标");

	DEF_F32插座数据(f_get输入插座(1)) = 1.0;
	(DEF_UI32插座数据(f_get输入插座(2))) = 32;
}

C_圆坐标生成节点::~C_圆坐标生成节点() {
}

bool C_圆坐标生成节点::f_update() {
	auto 半径 = DEF_F32插座数据(f_get输入插座(1));
	auto 细分 = DEF_UI32插座数据(f_get输入插座(2));

	auto* vert = DEF_Vec3插座_1D数据(f_get输出插座(1));
	f_core_array_resize((S_Array*)vert, 细分);
	
	f_graph_计算圆坐标v3({}, 半径, 细分, vert->ptr_userData);
	return false;
}

std::string C_圆坐标生成节点::f_编译(C_节点基类* rn, std::string& 声明, std::vector<std::string>& 定义, std::string& 释放) {
	m_Code = "";
	std::string 新变量 = f_getName();
	

	C_节点树* rt = f_getThis节点树();

	
	//m_Code += "{\n";
	m_Code += f_get输入插座(1)->f_构建变量代码(0);
	m_Code += f_get输入插座(2)->f_构建变量代码(0);
	std::string 半径 = f_get输入插座(1)->f_getCode(0);
	std::string 数量 = f_get输入插座(2)->f_getCode(0);
	
	std::string 数量_取负数 = 新变量;
	m_Code += f_代码构建_新建变量忽略负数(数量, 数量_取负数);
	m_Code += f_代码构建_创建vec3_Array(新变量, 数量_取负数);

	
	

	m_Code += DEF_S(f_graph_计算圆坐标v3_JIT);
	m_Code += "({}, " + 半径 + "," + 数量_取负数 + ", " + 新变量 + ");\n";

	m_Code += m_ReleaseCode;
	//m_Code += "}\n";

	f_get输出插座(1)->f_setCode(新变量);
	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;
		m_区域父节点->m_ReleaseCode += f_代码构建_销毁数组(新变量);
		return "";
	}
	else {
		释放 += f_代码构建_销毁数组(新变量);
	}

	return m_Code;
}

void C_圆坐标生成节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		//下一次读取数据指针 = f_prop_Load(m_计算类型, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_圆坐标生成节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);

	auto 文件块 = f_file_构建文件块信息(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_节点数据::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	//f_prop_Save(m_计算类型, 块);

	文件块.m_data = 块->ptr_userData;
	文件块.m_字节数 = 块->count;
	f_file_保存文件块(f, 文件块);
	f_core_array_free((S_Array*)块);
}

C_节点基类* f_node_创建圆坐标生成节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_圆坐标生成节点(ctx);
}

C_节点基类* f_node_加载圆坐标生成节点(S_设备环境& ctx, FILE* f) {
	C_圆坐标生成节点* node = new C_圆坐标生成节点(ctx);
	return node;
}

void f_node_保存圆坐标生成节点(C_节点基类* n, FILE* f) {
	C_圆坐标生成节点* node = dynamic_cast<C_圆坐标生成节点*>(n);
}




C_直线坐标生成节点::C_直线坐标生成节点(S_设备环境& ctx) : C_节点基类(DEF_直线坐标生成节点) {
	m_Ctx = ctx;
	m_Name = L"直线";

	C_插座基类* socket;
	DEF_创建Vec3插座_I(L"方向", nullptr);
	DEF_创建F32插座_I(L"长度", nullptr);
	DEF_创建UI32插座_I(L"细分", nullptr);

	DEF_创建Vec3_1D插座_O(L"顶点");

	DEF_Vec3插座数据(f_get输入插座(1)) = { 0,1,0 };
	DEF_F32插座数据(f_get输入插座(2)) = 1;
	DEF_UI32插座数据(f_get输入插座(3)) = 1;
}

C_直线坐标生成节点::~C_直线坐标生成节点() {
}

bool C_直线坐标生成节点::f_update() {
	auto 方向 = DEF_Vec3插座数据(f_get输入插座(1));
	auto 长度 = DEF_F32插座数据(f_get输入插座(2));
	auto 细分 = DEF_UI32插座数据(f_get输入插座(3));

	auto vert = DEF_Vec3插座_1D数据(f_get输出插座(1));
	++细分;
	长度 /= 细分;

	f_core_array_resize((S_Array*)vert, 细分 + 1);
	auto* vert_ptr = vert->ptr_userData;

	方向 = vec_normalize(方向);
	
	for (uint32 i = 0; i <= 细分; ++i) {
		vert_ptr[i] = 方向 * (长度*i);
	}

	return false;
}

std::string C_直线坐标生成节点::f_编译(C_节点基类* rn, std::string& 声明, std::vector<std::string>& 定义, std::string& 释放) {
	m_Code = "";
	std::string 新变量 = f_getName();
	


	C_节点树* rt = f_getThis节点树();

	m_Code += f_get输入插座(1)->f_构建变量代码(0);
	m_Code += f_get输入插座(2)->f_构建变量代码(0);
	m_Code += f_get输入插座(3)->f_构建变量代码(0);
	std::string 方向 = f_get输入插座(1)->f_getCode(0);
	std::string 长度 = f_get输入插座(2)->f_getCode(0);
	std::string 细分 = f_get输入插座(3)->f_getCode(0);

	
	std::string 细分_取负数 = 新变量 + "_细分";
	m_Code += f_代码构建_新建变量忽略负数(细分, 细分_取负数);
	
	m_Code += f_代码构建_创建vec3_Array(新变量, 细分_取负数);

	m_Code += DEF_S(f_graph_计算直线坐标);
	m_Code += "(" + 方向 + ", " + 长度 + ", " + 细分_取负数 + ", " + 新变量 + ");\n";

	m_Code += m_ReleaseCode;
	

	f_get输出插座(1)->f_setCode(新变量);
	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;
		m_区域父节点->m_ReleaseCode += f_代码构建_销毁数组(新变量);
		return "";
	}
	else {
		释放 += f_代码构建_销毁数组(新变量);
	}

	return m_Code;
}

void C_直线坐标生成节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		//下一次读取数据指针 = f_prop_Load(m_计算类型, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_直线坐标生成节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_file_构建文件块信息(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_节点数据::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	//f_prop_Save(m_计算类型, 块);

	文件块.m_data = 块->ptr_userData;
	文件块.m_字节数 = 块->count;
	f_file_保存文件块(f, 文件块);
	f_core_array_free((S_Array*)块);
}

C_节点基类* f_node_创建直线坐标生成节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_直线坐标生成节点(ctx);
}

C_节点基类* f_node_加载直线坐标生成节点(S_设备环境& ctx, FILE* f) {
	C_直线坐标生成节点* node = new C_直线坐标生成节点(ctx);
	return node;
}

void f_node_保存直线坐标生成节点(C_节点基类* n, FILE* f) {
	C_直线坐标生成节点* node = dynamic_cast<C_直线坐标生成节点*>(n);
}




C_平面坐标生成节点::C_平面坐标生成节点(S_设备环境& ctx) : C_节点基类(DEF_平面坐标生成节点) {
	m_Ctx = ctx;
	m_Name = L"直线";

	C_插座基类* socket;
	DEF_创建Vec3插座_I(L"大小", nullptr);
	DEF_创建uVec3插座_I(L"细分", nullptr);

	DEF_创建Vec3_1D插座_O(L"顶点");

	DEF_Vec3插座数据(f_get输入插座(1)) = { 1,1,1 };
	*DEF_uVec3插座数据(f_get输入插座(2)) = {1,1,1};
}

C_平面坐标生成节点::~C_平面坐标生成节点() {
}

bool C_平面坐标生成节点::f_update() {
	return false;
}

std::string C_平面坐标生成节点::DEF_节点编译函数 {
    m_Code = "";
	m_ReleaseCode = "";
	std::string name = f_getName();

	//C_节点树* rt = f_getThis节点树();
	m_Code += f_get输入插座(1)->f_构建变量代码(0);
	m_Code += f_get输入插座(2)->f_构建变量代码(0);
	std::string 方向 = f_get输入插座(1)->f_getCode(0);
	std::string 长度 = f_get输入插座(2)->f_getCode(0);

	m_Code += DEF_S(S_Vec3Array*)" " + name + " = " + f_代码构建_创建Array(E_值类型::e_Type_Vec3_1D, "1") + ";\n";

	m_Code += DEF_S(f_graph_构建平面坐标);
	m_Code += "(" + f_get输入插座(1)->f_getCode(0) + ", " + f_get输入插座(2)->f_getCode(0) + ", " + name + ");\n";

	m_Code += m_ReleaseCode;


	f_get输出插座(1)->f_setCode(name);
	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;
		m_区域父节点->m_ReleaseCode += f_代码构建_销毁数组(name);
		return "";
	}
	else {
		释放 += f_代码构建_销毁数组(name);
	}

	return m_Code;
}

void C_平面坐标生成节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);

	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		//下一次读取数据指针 = f_prop_Load(m_计算类型, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_平面坐标生成节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);

	auto 文件块 = f_file_构建文件块信息(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_节点数据::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	//f_prop_Save(m_计算类型, 块);

	文件块.m_data = 块->ptr_userData;
	文件块.m_字节数 = 块->count;
	f_file_保存文件块(f, 文件块);
	f_core_array_free((S_Array*)块);
}

C_节点基类* f_node_创建平面坐标生成节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_平面坐标生成节点(ctx);
}

C_节点基类* f_node_加载平面坐标生成节点(S_设备环境& ctx, FILE* f) {
	C_平面坐标生成节点* node = new C_平面坐标生成节点(ctx);
	return node;
}

void f_node_保存平面坐标生成节点(C_节点基类* n, FILE* f) {
	C_平面坐标生成节点* node = dynamic_cast<C_平面坐标生成节点*>(n);
}






C_曲线采样节点::C_曲线采样节点(S_设备环境& ctx) : C_节点基类(DEF_曲线采样节点) {
	m_Ctx = ctx;
	m_Name = L"曲线";

	C_插座基类* socket;
	DEF_创建Vec2_Array1D插座_I(L"控制点", nullptr);
	DEF_创建F32插座_I(L"采样系数", nullptr);
	DEF_创建F32插座_O(L"值", nullptr);
	
	//m_曲线类型 = f_alloc_EnumProp({ {L""}})
}

C_曲线采样节点::~C_曲线采样节点() {
}

bool C_曲线采样节点::f_update() {

	return false;
}

std::string C_曲线采样节点::f_编译(C_节点基类* rn, std::string& 声明, std::vector<std::string>& 定义, std::string& 释放) {
	m_Code = "";
	std::string val_name = f_getName() + "梯度采样";
	m_Code += "float32 " + val_name;

	m_Code += "{\n";
	auto 控制点 = f_get输入插座(1)->f_构建变量代码(0);
	auto 采样系数 = f_get输入插座(2)->f_构建变量代码(0);

	m_Code += m_ReleaseCode;
	m_Code += "}\n";

	
	f_get输出插座(1)->f_setCode(val_name);

	return m_Code;
}

void C_曲线采样节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);

	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		//下一次读取数据指针 = f_prop_Load(m_计算类型, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_曲线采样节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);

	auto 文件块 = f_file_构建文件块信息(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_节点数据::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	//f_prop_Save(m_计算类型, 块);

	文件块.m_data = 块->ptr_userData;
	文件块.m_字节数 = 块->count;
	f_file_保存文件块(f, 文件块);
	f_core_array_free((S_Array*)块);
}

C_节点基类* f_node_创建曲线采样节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_曲线采样节点(ctx);
}

C_节点基类* f_node_加载曲线采样节点(S_设备环境& ctx, FILE* f) {
	C_曲线采样节点* node = new C_曲线采样节点(ctx);
	return node;
}

void f_node_保存曲线采样节点(C_节点基类* n, FILE* f) {
	C_曲线采样节点* node = static_cast<C_曲线采样节点*>(n);
}





void on_曲线数据Update(S_Props& prop) {
	
}

C_渐变采样节点::C_渐变采样节点(S_设备环境& ctx) : C_节点基类(DEF_渐变采样节点) {
	m_Ctx = ctx;
	m_Name = L"渐变";

	C_插座基类* socket;
	DEF_创建F32插座_I(L"采样系数", nullptr);
	DEF_创建Vec2_1D插座_I(L"控制点", nullptr);
	DEF_创建Vec2插座_I(L"钳制", nullptr);
	
	DEF_创建F32插座_O(L"值", nullptr);


	(DEF_Vec2插座数据(f_get输入插座(3), 0)) = {0,1};


	m_曲线 = f_alloc_2DCurveProp(nullptr, L"曲线");
	m_曲线.m_私有 = true;

	//m_曲线GPU区间 = f_alloc_uVec2Prop(nullptr, L"曲线项");
	//m_曲线GPU区间.m_私有 = true;
	//f_prop_uVec2(m_曲线GPU区间) = {};

	f_构建代码_分配渲染器GPU插座变量(*f_get输入插座(1));
	f_构建代码_分配渲染器GPU插座变量(*f_get输入插座(3));
	//f_构建代码_分配渲染器GPU属性变量(m_曲线GPU区间);
	f_构建代码_分配渲染器GPU属性变量(m_曲线);

}

C_渐变采样节点::~C_渐变采样节点() {
	f_构建代码_释放渲染器GPU插座变量(*f_get输入插座(1));
	f_构建代码_释放渲染器GPU插座变量(*f_get输入插座(3));
	//f_构建代码_释放渲染器GPU属性变量(m_曲线GPU区间);
	f_构建代码_释放渲染器GPU属性变量(m_曲线);

	f_prop_Release(m_曲线);
}

bool C_渐变采样节点::f_update() {
	auto inSocketA = f_get输入插座(1);

	float32 采样系数 = DEF_F32插座数据(f_get输入插座(2));

	if (inSocketA->f_isLink()) {

	}
	else {
		float32 采样结果 = f_graph_钳制曲线采样(采样系数, *f_prop_2DCurve(m_曲线));
		f_get输出插座(1)->f_setData(&采样结果);
	}

	return false;
}

std::string C_渐变采样节点::f_编译(C_节点基类* rn, std::string& 声明, std::vector<std::string>& 定义, std::string& 释放) {
	m_Code = "";
	m_ReleaseCode = "";
	bool 创建数组 = false;
	std::string name = f_getName() + "curveSample";
	auto* rt = f_getThis节点树();

	auto socket1 = f_get输入插座(1);
	auto socket2 = f_get输入插座(2);
	auto socket3 = f_get输入插座(3);
	if (socket1->f_get接入的数据类型() == E_值类型::e_Type_F32 || !socket1->f_isLink()) {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_F32);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32);
		创建数组 = false;
		m_Code += "float " + name + ";\n";
	}
	else {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_F32_1D);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32_1D);
		创建数组 = true;
		m_Code += DEF_S(S_F32Array*)" " + name + ";\n";
	}
	socket1 = f_get输入插座(1);


	m_Code += "{\n";
	m_Code += socket1->f_构建变量代码(0);
	m_Code += socket2->f_构建变量代码(0);
	m_Code += socket3->f_构建变量代码(0);


	if (rt->m_树类型 == E_节点树类型::e_type_着色节点树) {
		m_Code += name + " = " + DEF_S(f_glsl_CurveSample);
		m_Code += "(" + socket1->f_getCode(0) + ", " + f_代码构建_属性变量(m_曲线, rt) + ", " + socket3->f_getCode(0) + ");\n";

		f_prop_采样曲线拷贝到GPU(m_曲线);
		f_su_数据拷贝到GPU(socket3);
	}
	else {
		if (创建数组) {
			m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_F32_1D, "1") + ";\n";
			m_Code += DEF_S(f_JIT_曲线采样);
			m_Code += "(" + name + ", " + f_代码构建_属性变量(m_曲线, rt) + ", " + socket1->f_getCode(0) + ", " + socket3->f_getCode(0) + ");\n";

			socket3->m_GPU缓存;
		}
		else {
			m_Code += name + " = ";
			m_Code += DEF_S(f_graph_钳制曲线采样);
			m_Code += "(" + socket1->f_getCode(0) + ", ";

			if (socket2->f_isLink()) {
				m_Code += socket2->f_构建变量代码(0);
				m_Code += socket2->f_getCode(0) + ",";
			}
			else {
				auto* rt = f_getThis节点树();
				auto 控制点 = f_代码构建_属性变量(m_曲线, rt);
				m_Code += 控制点 + ",";
			}
			m_Code += socket3->f_getCode(0);
			m_Code += ");\n";
		}


		m_Code += m_ReleaseCode;
	}
	
	m_Code += "}\n";



	f_get输出插座(1)->f_setCode(name);

	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;
		if (创建数组) {
			m_区域父节点->m_ReleaseCode += f_代码构建_销毁数组(name);
		}
		return "";
	}
	if (创建数组) {
		释放 += f_代码构建_销毁数组(name);
	}
	return m_Code;
}

void C_渐变采样节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		if (f_file_版本对比(文件块, S_节点数据::g_低版本号_0, S_节点数据::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_曲线, 下一次读取数据指针);
		}
	}
	free(文件块.m_data);
}

void C_渐变采样节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_file_构建文件块信息(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_节点数据::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_曲线, 块);

	f_file_保存文件块(f, 文件块, 块);
}

void C_渐变采样节点::f_Copy(const C_节点基类* node) {
	auto* 渐变采样节点 = dynamic_cast<const C_渐变采样节点*>(node);
	const S_曲线* 曲线 = f_prop_2DCurve(渐变采样节点->m_曲线);
	f_core_array_copy((S_Array*)f_prop_2DCurve(m_曲线), (S_Array*)曲线);
}

C_节点基类* f_node_创建渐变采样节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_渐变采样节点(ctx);
}

C_节点基类* f_node_加载渐变采样节点(S_设备环境& ctx, FILE* f) {
	C_渐变采样节点* node = new C_渐变采样节点(ctx);
	return node;
}

void f_node_保存渐变采样节点(C_节点基类* n, FILE* f) {
	C_渐变采样节点* node = static_cast<C_渐变采样节点*>(n);
}




C_绕点旋转节点::C_绕点旋转节点(S_设备环境& ctx) : C_节点基类(DEF_绕点旋转节点) {
	m_Name = L"绕点旋转";
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建Vec3插座_I(L"点", nullptr);
	DEF_创建Vec3插座_I(L"轴向", nullptr);
	DEF_创建F32插座_I(L"弧度", nullptr);
	DEF_创建Vec3插座_I(L"中心", nullptr);

	DEF_创建Vec3插座_O(L"点");

	m_曲线 = f_alloc_2DCurveProp(nullptr, L"曲线");
	m_曲线.m_私有 = true;
}

C_绕点旋转节点::~C_绕点旋转节点() {
	f_prop_Release(m_曲线);
}

#define _DEF_绕点旋转节点_插座类型转换_                                                           \
创建数组 = socket1->f_get接入的数据类型() == E_值类型::e_Type_Vec3_1D       ||                    \
                 socket2->f_get接入的数据类型() == E_值类型::e_Type_Vec3_1D ||                    \
                 socket3->f_get接入的数据类型() == E_值类型::e_Type_F32_1D;                       \
if (!创建数组 || (!socket1->f_isLink() && !socket2->f_isLink() && !socket3->f_isLink()) ) {       \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3);           \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_Vec3);           \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 3, E_值类型::e_Type_F32);            \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3);           \
	创建数组 = false;                                                                             \
}                                                                                                 \
else {                                                                                            \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3_1D);        \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_Vec3_1D);        \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 3, E_值类型::e_Type_F32_1D);         \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3_1D);        \
	创建数组 = true;                                                                              \
}                                                                                                 \
socket1 = f_get输入插座(1);                                                                       \
socket2 = f_get输入插座(2);                                                                       \
socket3 = f_get输入插座(3);  

bool C_绕点旋转节点::f_update() {
	return false;
}

std::string C_绕点旋转节点::DEF_节点编译函数{
	m_Code = "";
	m_ReleaseCode = "";
	std::string name = f_getName();

	bool 创建数组 = false;
	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);
	auto* socket3 = f_get输入插座(3);
	auto* socket4 = f_get输入插座(4);
	_DEF_绕点旋转节点_插座类型转换_;

	if (创建数组) {
		m_Code += DEF_S(S_Vec3Array*)"   " + name + ";\n";
	}
	else {
		m_Code += "float32 " + name + ";\n";
	}
	
	m_Code += "{\n";

	m_Code += socket1->f_构建变量代码(0);
	m_Code += socket2->f_构建变量代码(0);
	m_Code += socket3->f_构建变量代码(0);
	m_Code += socket4->f_构建变量代码(0);

	if (创建数组) {
		m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_Vec3_1D, "1") + ";\n";
		m_Code += DEF_S(f_math_绕点旋转m)"(" + name + ", " + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + socket3->f_getCode(0) + ", " + socket4->f_getCode(0) + ");\n";
	}
	else {
		m_Code += name + ";\n";
		m_Code += DEF_S(f_math_绕点旋转)"(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + socket3->f_getCode(0) + ", " + socket4->f_getCode(0) + ");\n";
	}

	m_Code += m_ReleaseCode;
	m_Code += "}\n";



	f_get输出插座(1)->f_setCode(name);

	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;
		if (创建数组) {
			m_区域父节点->m_ReleaseCode += f_代码构建_销毁数组(name);
		}
		return "";
	}
	if (创建数组) {
		释放 += f_代码构建_销毁数组(name);
	}
	return m_Code;
}

void C_绕点旋转节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		下一次读取数据指针 = f_prop_Load(m_曲线, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_绕点旋转节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_file_构建文件块信息(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_节点数据::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_曲线, 块);

	文件块.m_data = 块->ptr_userData;
	文件块.m_字节数 = 块->count;
	f_file_保存文件块(f, 文件块);
	f_core_array_free((S_Array*)块);
}

C_节点基类* f_node_创建绕点旋转节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_绕点旋转节点(ctx);
}

C_节点基类* f_node_加载绕点旋转节点(S_设备环境& ctx, FILE* f) {
	C_绕点旋转节点* node = new C_绕点旋转节点(ctx);
	return node;
}

void f_node_保存绕点旋转节点(C_节点基类* n, FILE* f) {
	C_绕点旋转节点* node = static_cast<C_绕点旋转节点*>(n);
}



C_步进计算节点::C_步进计算节点(S_设备环境& ctx) : C_节点基类(DEF_步进计算节点) {
	m_Name = L"步进";
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建F32插座_I(L"x", nullptr);
	DEF_创建F32插座_I(L"edge", nullptr);
	
	DEF_创建F32插座_O(L"a", nullptr);

	DEF_F32插座数据(f_get输入插座(2)) = 1;

	m_步进方式 = f_alloc_EnumProp(nullptr, {
		{L"step"},
		{L"间隔"},
		{L"循环"},
		{L"滴答"},
		{L"累加"},
		{L"累减"},
	}, L"步进方式");
	m_步进方式.m_私有 = true;
}

C_步进计算节点::~C_步进计算节点() {
	f_prop_Release(m_步进方式);
}

void C_步进计算节点::f_插座兼容切换(bool& 创建数组, bool& 创建浮点) {
	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);

	if (!socket1->f_isLink() && !socket1->f_isLink()) {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_F32);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_F32);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32);
	}

	auto 接入的数据类型1 = socket1->f_get接入的数据类型();
	auto 接入的数据类型2 = socket2->f_get接入的数据类型();

	创建数组 = f_代码构建_是否为数组(接入的数据类型1) || f_代码构建_是否为数组(接入的数据类型2);
	if (创建数组) {
		创建浮点 = f_代码构建_是否为单值数组浮点(接入的数据类型1) || f_代码构建_是否为单值数组浮点(接入的数据类型2);

		if (创建浮点) {
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_F32_1D);
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_F32_1D);
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32_1D);
		}
		else {
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_I32_1D);
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_I32_1D);
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_I32_1D);
		}
	}
	else {
		创建浮点 = f_代码构建_是否为单值浮点(接入的数据类型1) || f_代码构建_是否为单值浮点(接入的数据类型2);

		if (创建浮点) {
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_F32);
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_F32);
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32);
		}
		else {
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_I32);
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_I32);
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_I32);
		}
	}
}

bool C_步进计算节点::f_update() {
	bool 创建数组 = false;
	bool 创建浮点 = false;

	f_插座兼容切换(创建数组, 创建浮点);
	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);
	auto* outSocket1 = f_get输出插座(1);

	if (创建数组) {
		if (创建浮点) {
			f_JIT_步进fm(DEF_F32插座_1D数据(socket1), DEF_F32插座_1D数据(socket2), DEF_F32插座_1D数据(outSocket1), f_prop_enum(m_步进方式));
		}
		else {
			f_JIT_步进im(DEF_I32插座_1D数据(socket1), DEF_I32插座_1D数据(socket2), DEF_I32插座_1D数据(outSocket1), f_prop_enum(m_步进方式));
		}
	}
	else {
		if (创建浮点) {
			DEF_F32插座数据(outSocket1) = f_JIT_步进f(DEF_F32插座数据(socket1), DEF_F32插座数据(socket2), f_prop_enum(m_步进方式));
		}
		else {
			DEF_I32插座数据(outSocket1) = f_JIT_步进i(DEF_I32插座数据(socket1), DEF_I32插座数据(socket2), f_prop_enum(m_步进方式));
		}
	}
	return false;
}

std::string C_步进计算节点::DEF_节点编译函数{
	m_Code = "";
	m_ReleaseCode = "";
	std::string name = f_getName();

	bool 创建数组 = false;
	bool 创建浮点 = false;
	
	f_插座兼容切换(创建数组, 创建浮点);
	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);


	if (创建数组) {
		if(创建浮点) m_Code += DEF_S(S_F32Array*)"   " + name + ";\n";
		else m_Code += DEF_S(S_I32Array*)"   " + name + ";\n";
	}
	else {
		if (创建浮点) m_Code += "float32 " + name + ";\n";
		else m_Code += "int32 " + name + ";\n";
	}


	m_Code += "{\n";
	m_Code += socket1->f_构建变量代码(0);
	m_Code += socket2->f_构建变量代码(0);

	auto c1 = socket1->f_getCode(0);
	auto c2 = socket2->f_getCode(0);
	auto c3 = f_代码构建_属性变量(m_步进方式, f_getThis节点树());

	if (创建数组) {
		if (创建浮点) {
			m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_Vec3_1D, "1") + ";\n";
			m_Code += DEF_S(f_JIT_步进fm)"(" + c1 + ", " + c2 + ", " + name + ", " + c3 + ");\n";
		}
		else {
			m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_I32_1D, "1") + ";\n";
			m_Code += DEF_S(f_JIT_步进im)"(" + c1 + ", " + c2 + ", " + name + ", " + c3 + ");\n";
		}
	}
	else {
		if (创建浮点) {
			m_Code += name + " = " + DEF_S(f_JIT_步进f)"(" + c1 + ", " + c2 + ", " + c3 + ");\n";
		}
		else {
			m_Code += name + " = " + DEF_S(f_JIT_步进i)"(" + c1 + ", " + c2 + ", " + c3 + ");\n";
		}
	}

	m_Code += m_ReleaseCode;
	m_Code += "}\n";



	f_get输出插座(1)->f_setCode(name);

	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;
		if (创建数组) {
			m_区域父节点->m_ReleaseCode += f_代码构建_销毁数组(name);
		}
		return "";
	}
	if (创建数组) {
		释放 += f_代码构建_销毁数组(name);
	}
	return m_Code;
}

void C_步进计算节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		下一次读取数据指针 = f_prop_Load(m_步进方式, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_步进计算节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_file_构建文件块信息(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_节点数据::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_步进方式, 块);

	文件块.m_data = 块->ptr_userData;
	文件块.m_字节数 = 块->count;
	f_file_保存文件块(f, 文件块);
	f_core_array_free((S_Array*)块);
}

C_节点基类* f_node_创建步进计算节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_步进计算节点(ctx);
}

C_节点基类* f_node_加载步进计算节点(S_设备环境& ctx, FILE* f) {
	C_步进计算节点* node = new C_步进计算节点(ctx);
	return node;
}

void f_node_保存步进计算节点(C_节点基类* n, FILE* f) {
	C_步进计算节点* node = static_cast<C_步进计算节点*>(n);
}





//C_累加器节点::C_累加器节点(S_设备环境& ctx) : C_节点基类(DEF_步进计算节点) {
//	m_Name = L"步进";
//	m_Ctx = ctx;
//
//	C_插座基类* socket;
//	DEF_创建I32插座_I(L"x", nullptr);
//	DEF_创建I32插座_I(L"edge", nullptr);
//
//	DEF_创建F32插座_O(L"a", nullptr);
//
//	DEF_F32插座数据(f_get输入插座(2)) = 1;
//
//	m_步进方式 = f_alloc_EnumProp(nullptr, {
//		{L"step"},
//		{L"间隔"},
//		{L"循环"},
//		{L"滴答"},
//							  }, L"步进方式");
//	m_步进方式.m_私有 = true;
//}
//
//C_累加器节点::~C_累加器节点() {
//	f_prop_Release(m_步进方式);
//}



